using System;
using System.Collections.Generic;
using System.IO;
using System.Net.Http;
using System.Text;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;

namespace DocumentCreationSystem.Services
{
    /// <summary>
    /// Ollama模型拉取进度信息
    /// </summary>
    public class OllamaModelPullProgress
    {
        public string Status { get; set; } = "";
        public string Digest { get; set; } = "";
        public long Total { get; set; }
        public long Completed { get; set; }
        public double ProgressPercentage => Total > 0 ? (double)Completed / Total * 100 : 0;
        public string ProgressText { get; set; } = "";
        public bool IsCompleted { get; set; }
        public bool IsError { get; set; }
        public string ErrorMessage { get; set; } = "";
    }

    /// <summary>
    /// Ollama模型拉取服务
    /// </summary>
    public class OllamaModelPullService
    {
        private readonly ILogger<OllamaModelPullService> _logger;
        private readonly HttpClient _httpClient;

        public OllamaModelPullService(ILogger<OllamaModelPullService> logger)
        {
            _logger = logger;
            _httpClient = new HttpClient();
            _httpClient.Timeout = TimeSpan.FromHours(2); // 模型下载可能需要很长时间
        }

        /// <summary>
        /// 拉取Ollama模型并提供进度回调
        /// </summary>
        /// <param name="baseUrl">Ollama服务地址</param>
        /// <param name="modelName">模型名称</param>
        /// <param name="progressCallback">进度回调</param>
        /// <param name="cancellationToken">取消令牌</param>
        /// <returns>是否成功</returns>
        public async Task<bool> PullModelAsync(
            string baseUrl, 
            string modelName, 
            IProgress<OllamaModelPullProgress>? progressCallback = null,
            CancellationToken cancellationToken = default)
        {
            try
            {
                _logger.LogInformation($"开始拉取Ollama模型: {modelName}");
                
                var pullUrl = $"{baseUrl.TrimEnd('/')}/api/pull";
                var requestBody = new { name = modelName };
                var json = JsonSerializer.Serialize(requestBody);
                var content = new StringContent(json, Encoding.UTF8, "application/json");

                progressCallback?.Report(new OllamaModelPullProgress
                {
                    Status = "正在连接Ollama服务...",
                    ProgressText = "初始化下载"
                });

                using var response = await _httpClient.PostAsync(pullUrl, content, cancellationToken);
                
                if (!response.IsSuccessStatusCode)
                {
                    var errorContent = await response.Content.ReadAsStringAsync();
                    var errorMsg = $"HTTP {response.StatusCode}: {errorContent}";
                    _logger.LogError($"拉取模型失败: {errorMsg}");
                    
                    progressCallback?.Report(new OllamaModelPullProgress
                    {
                        IsError = true,
                        ErrorMessage = errorMsg,
                        Status = "下载失败"
                    });
                    return false;
                }

                // 处理流式响应
                using var stream = await response.Content.ReadAsStreamAsync();
                using var reader = new StreamReader(stream);

                var lastProgress = new OllamaModelPullProgress();
                
                while (!reader.EndOfStream && !cancellationToken.IsCancellationRequested)
                {
                    var line = await reader.ReadLineAsync();
                    if (string.IsNullOrWhiteSpace(line)) continue;

                    try
                    {
                        var progressInfo = JsonSerializer.Deserialize<JsonElement>(line);
                        var progress = ParseProgressInfo(progressInfo, modelName);
                        
                        // 只在进度有显著变化时报告
                        if (ShouldReportProgress(progress, lastProgress))
                        {
                            progressCallback?.Report(progress);
                            lastProgress = progress;
                            
                            _logger.LogDebug($"模型拉取进度: {progress.Status} - {progress.ProgressPercentage:F1}%");
                        }

                        if (progress.IsCompleted)
                        {
                            _logger.LogInformation($"模型 {modelName} 拉取完成");
                            return true;
                        }
                    }
                    catch (JsonException ex)
                    {
                        _logger.LogWarning(ex, $"解析进度信息失败: {line}");
                    }
                }

                if (cancellationToken.IsCancellationRequested)
                {
                    _logger.LogInformation($"模型 {modelName} 拉取被取消");
                    progressCallback?.Report(new OllamaModelPullProgress
                    {
                        Status = "下载已取消",
                        IsError = true,
                        ErrorMessage = "用户取消了下载"
                    });
                    return false;
                }

                return true;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, $"拉取模型 {modelName} 时发生异常");
                progressCallback?.Report(new OllamaModelPullProgress
                {
                    IsError = true,
                    ErrorMessage = ex.Message,
                    Status = "下载异常"
                });
                return false;
            }
        }

        /// <summary>
        /// 解析Ollama API返回的进度信息
        /// </summary>
        private OllamaModelPullProgress ParseProgressInfo(JsonElement progressInfo, string modelName)
        {
            var progress = new OllamaModelPullProgress();

            if (progressInfo.TryGetProperty("status", out var statusElement))
            {
                progress.Status = statusElement.GetString() ?? "";
            }

            if (progressInfo.TryGetProperty("digest", out var digestElement))
            {
                progress.Digest = digestElement.GetString() ?? "";
            }

            if (progressInfo.TryGetProperty("total", out var totalElement))
            {
                progress.Total = totalElement.GetInt64();
            }

            if (progressInfo.TryGetProperty("completed", out var completedElement))
            {
                progress.Completed = completedElement.GetInt64();
            }

            // 生成友好的进度文本
            progress.ProgressText = GenerateProgressText(progress, modelName);

            // 检查是否完成
            progress.IsCompleted = progress.Status.Contains("success") || 
                                 progress.Status.Contains("完成") ||
                                 (progress.Total > 0 && progress.Completed >= progress.Total);

            return progress;
        }

        /// <summary>
        /// 生成友好的进度文本
        /// </summary>
        private string GenerateProgressText(OllamaModelPullProgress progress, string modelName)
        {
            if (progress.Total > 0)
            {
                var totalMB = progress.Total / (1024.0 * 1024.0);
                var completedMB = progress.Completed / (1024.0 * 1024.0);
                
                return $"下载 {modelName}: {completedMB:F1}MB / {totalMB:F1}MB ({progress.ProgressPercentage:F1}%)";
            }
            else
            {
                return progress.Status switch
                {
                    "pulling manifest" => $"正在获取 {modelName} 的清单信息...",
                    "downloading" => $"正在下载 {modelName}...",
                    "verifying sha256 digest" => $"正在验证 {modelName} 的完整性...",
                    "writing manifest" => $"正在写入 {modelName} 的清单...",
                    "removing any unused layers" => $"正在清理 {modelName} 的临时文件...",
                    "success" => $"模型 {modelName} 下载完成！",
                    _ => $"{progress.Status} - {modelName}"
                };
            }
        }

        /// <summary>
        /// 判断是否应该报告进度（避免过于频繁的更新）
        /// </summary>
        private bool ShouldReportProgress(OllamaModelPullProgress current, OllamaModelPullProgress last)
        {
            // 状态改变时总是报告
            if (current.Status != last.Status) return true;
            
            // 完成时总是报告
            if (current.IsCompleted) return true;
            
            // 进度变化超过1%时报告
            if (Math.Abs(current.ProgressPercentage - last.ProgressPercentage) >= 1.0) return true;
            
            // 每10MB报告一次
            if (current.Total > 0 && Math.Abs(current.Completed - last.Completed) >= 10 * 1024 * 1024) return true;
            
            return false;
        }

        /// <summary>
        /// 检查模型是否已存在
        /// </summary>
        public async Task<bool> IsModelExistsAsync(string baseUrl, string modelName)
        {
            try
            {
                var tagsUrl = $"{baseUrl.TrimEnd('/')}/api/tags";
                var response = await _httpClient.GetStringAsync(tagsUrl);
                
                var options = new JsonSerializerOptions
                {
                    PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
                    PropertyNameCaseInsensitive = true
                };
                
                var result = JsonSerializer.Deserialize<JsonElement>(response, options);
                
                if (result.TryGetProperty("models", out var modelsElement) && modelsElement.ValueKind == JsonValueKind.Array)
                {
                    foreach (var model in modelsElement.EnumerateArray())
                    {
                        if (model.TryGetProperty("name", out var nameElement))
                        {
                            var name = nameElement.GetString();
                            if (name == modelName || name?.StartsWith($"{modelName}:") == true)
                            {
                                return true;
                            }
                        }
                    }
                }
                
                return false;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, $"检查模型 {modelName} 是否存在时发生错误");
                return false;
            }
        }

        public void Dispose()
        {
            _httpClient?.Dispose();
        }
    }
}
